package worldinruin.core.imp;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

import worldinruin.core.IMap;
import worldinruin.core.ITile;
import worldinruin.core.imp.tilemodels.FertileTile;
import worldinruin.core.imp.tilemodels.ForestTile;
import worldinruin.core.imp.tilemodels.GrassTile;
import worldinruin.core.imp.tilemodels.IronTile;
import worldinruin.core.imp.tilemodels.StoneTile;
import worldinruin.utils.IObservable;

public class Map implements IObservable, Serializable, IMap {
	
	private ITile[][] tiles;
	private LinkedList<ITile> tileList;
	private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
	private Random random = new Random();
	private String name = random.nextInt() + "";

	/**
	 * Creates a new map that can be used for games.
	 */
	public Map(){
		
		createNewInstance(8, 10, 20, 20, 20, 20);
		
	}


	/**
	 * Add tiles to a list that is used to make the map.
	 * @param tile Type of tile.
	 * @param amount Amount of that tile.
	 */
	private void addToList(ITile tile, int amount){
		
		for (int i = 0; i < amount; i++){
			tileList.add(tile);
		}
		
	}
	
	/* (non-Javadoc)
	 * @see worldinruin.core.imp.IMap#getNumberOfColumns()
	 */
	public int getNumberOfColumns(){
		return tiles[0].length;
	}
	
	/* (non-Javadoc)
	 * @see worldinruin.core.imp.IMap#getNumberOfRows()
	 */
	public int getNumberOfRows(){
		return tiles.length;
	}
	
	/* (non-Javadoc)
	 * @see worldinruin.core.imp.IMap#getTile(int, int)
	 */
	public ITile getTile(int row, int column){
		return tiles[row][column];
	}
	
	/* (non-Javadoc)
	 * @see worldinruin.core.imp.IMap#getTiles()
	 */
	public ITile[][] getTiles(){
		return tiles;
	}

	/**
	 * Creating the new map with all necessary information. Rest of tiles is 
	 * filled with grass tiles.
	 * @param numberOfRows Row index on map.
	 * @param numberOfColumns Column index on map.
	 * @param stone Number of stone tiles.
	 * @param iron Number of iron tiles.
	 * @param forest Number of forest tiles.
	 * @param fertile Number of fertile tiles.
	 */
	private void createNewInstance(int numberOfRows, int numberOfColumns, int stone, int iron,
			int forest, int fertile){
		
		tileList = new LinkedList<ITile>();
		tiles = new ITile[numberOfRows][numberOfColumns];
		
		addToList(new StoneTile(), stone);
		addToList(new IronTile(), iron);
		addToList(new ForestTile(), forest);
		addToList(new FertileTile(), fertile);
		
		//Fill the remaining slots with grass
		addToList(new GrassTile(), 100 - tileList.size());
		
				
		
		for (int row = 0; row < numberOfRows; row++){
			
			for (int column = 0; column < numberOfColumns; column++){
				
				int randomIndex = random.nextInt(tileList.size());				
				tiles[row][column] = tileList.get(randomIndex).newInstance(row, column);
				
			}
			
		}
		
	}
	
	/* (non-Javadoc)
	 * @see worldinruin.core.imp.IMap#updateMap(java.util.List)
	 */
	public void updateMap(List<ITile> newTiles) {
		 for (ITile tile : newTiles) {
			 tiles[tile.getRow()][tile.getColumn()] = tile;
		 }
	}


	/* (non-Javadoc)
	 * @see worldinruin.core.imp.IMap#addPropertyChangeListener(java.beans.PropertyChangeListener)
	 */
	@Override
	public void addPropertyChangeListener(PropertyChangeListener observer) {
		propertyChangeSupport.addPropertyChangeListener(observer);		
	}

	/* (non-Javadoc)
	 * @see worldinruin.core.imp.IMap#removePropertyChangeListener(java.beans.PropertyChangeListener)
	 */
	@Override
	public void removePropertyChangeListener(PropertyChangeListener observer) {
		propertyChangeSupport.removePropertyChangeListener(observer);
	}

	/* (non-Javadoc)
	 * @see worldinruin.core.imp.IMap#getName()
	 */
	public String getName() {
		return name;
	}

}
